import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'

// 原始数据结构（根据实际数据结构初始化）
const selected_course_data = ref()
const curriculum = ref()

const weekdayMap = {
  1: 'monday',
  2: 'tuesday',
  3: 'wednesday',
  4: 'thursday',
  5: 'friday',
  6: 'saturday',
  7: 'sunday',
}

// 工具函数：生成笛卡尔积
function cartesianProduct(args: any[]) {
  // 生成笛卡尔积
  return args.reduce(
    (a: any[], b: any[]) => a.flatMap((d: any) => b.map((e: any) => [d, e].flat())),
    [[]]
  )
}

function getClassGroup(code: string) {
  const base = code.replace(/01$/, '')
  return base.length > 0 ? base : code
}

function parseCourses(selected_course_data: any) {
  const courses = []
  for (const course of selected_course_data.Courses) {
    const classFragments = new Map()

    for (const Time of course.Time) {
      const timeSlot = Time.t
      for (const key of Object.keys(Time)) {
        if (key === 't') continue
        const day = parseInt(key)
        for (const fragment of Time[key]) {
          const groupKey = getClassGroup(fragment.c_c)
          const entry = {
            day,
            weeks: fragment.c_w,
            code: fragment.c_c,
            room: fragment.c_r,
            teacher: fragment.c_t,
            time_slot: timeSlot,
          }

          if (!classFragments.has(groupKey)) {
            classFragments.set(groupKey, [])
          }
          classFragments.get(groupKey).push(entry)
        }
      }
    }

    const courseOptions = []
    for (const [group, fragments] of classFragments.entries()) {
      courseOptions.push({
        name: course.Title,
        class_code: course.Code,
        code: group,
        fragments,
      })
    }

    courses.push({
      course_name: course.Title,
      options: courseOptions,
    })
  }
  return courses
}

// 检查内部课程是否冲突 true 冲突 false 不冲突
function hasConflict(frag1: any, frag2: any) {
  // 检查是否在同一周 是否有交集
  const commonWeeks = new Set(frag1.weeks.filter((w: any) => frag2.weeks.includes(w)))
  if (commonWeeks.size === 0) return false
  // 检查是否在同一天
  if (frag1.day !== frag2.day) return false
  // 检查是否在同一时间段
  return frag1.time_slot === frag2.time_slot
}
// 检查时间段冲突 true 冲突 false 不冲突
const checkTimeConflict = (newEntry: any, timeSlot: any) => {
  const existingEntries = timeSlot[newEntry.weekday] || []
  for (const entry of existingEntries) {
    // 获取课表课程的周数
    const existWeeks = new Set(
      entry.course_week_room.flatMap((cwr: any) => cwr.course_weeks).map(Number)
    )
    // 获取选择课程的周数
    const newWeeks = new Set(newEntry.weeks)

    // 检查是否在同一周 是否有交集
    if (new Set([...newWeeks].filter(w => existWeeks.has(w))).size === 0) {
      // 没有交集 肯定不冲突 跳过
      continue
    }
    // 有交集 检查是否在同一时间段
    if (newEntry.time === timeSlot.time) {
      // 冲突
      return true
    }
  }
  // 不冲突
  return false
}
// 检查课表是否符合要求 true 不冲突 false 冲突
function isValidSchedule(schedule: any, allowed: any) {
  // 创建临时课表副本
  const tempCurriculum = JSON.parse(JSON.stringify(curriculum.value))

  // 检查课程组合内部冲突
  const allFragments = schedule.flatMap((c: any) => c.fragments)
  for (let i = 0; i < allFragments.length; i++) {
    for (let j = i + 1; j < allFragments.length; j++) {
      if (hasConflict(allFragments[i], allFragments[j])) {
        // 冲突
        return false
      }
    }
  }

  // 检查与现有课表的冲突
  for (const courseSelection of schedule) {
    for (const frag of courseSelection.fragments) {
      // 创建新课表段
      const newEntry = {
        course_code: courseSelection.code,
        course_name: courseSelection.name,
        weeks: frag.weeks,
        time: selected_course_data.value.TimeMap[frag.time_slot].replace(/\r/g, ''),
        weekday: weekdayMap[frag.day as keyof typeof weekdayMap],
        teacher: frag.teacher,
        room: frag.room,
      }
      // 查找对应时间段
      const timeSlot = tempCurriculum.schedules.find((ts: any) => ts.time === newEntry.time)
      if (!timeSlot) continue
      // 插入旧课表检查是否冲突
      if (checkTimeConflict(newEntry, timeSlot)) {
        // 冲突
        return false
      }
      // 插入新课表段到旧课表 用于检查后面插入新的课表段
      if (!timeSlot[newEntry.weekday]) {
        timeSlot[newEntry.weekday] = []
      }
      timeSlot[newEntry.weekday].push({
        course_code: newEntry.course_code,
        course_name: newEntry.course_name,
        course_teacher: newEntry.teacher,
        course_week_room: [
          {
            course_room: newEntry.room,
            course_weeks: newEntry.weeks,
          },
        ],
      })
    }
  }

  // 检查允许时间段
  if (allowed && allowed.size > 0) {
    const d_s = allFragments.map((f: any) => [f.day, parseInt(f.time_slot.slice(1))])
    const d_s_arr = new Set(d_s.map((i: any) => JSON.stringify(i)))
    // 全部允许时间段
    return Array.from(allowed).every((i: any) => d_s_arr.has(i))
  }

  // 不冲突
  return true
}

// 使用示例
export function useTimetableGenerator() {
  const validSchedules = ref<any[]>([])
  const allCurriculums = ref<any[]>([])
  function generate(config: any) {
    selected_course_data.value = JSON.parse(
      localStorage.getItem('generate_selected_course_data') || '{}'
    )
    curriculum.value = JSON.parse(localStorage.getItem('generate_selected_curriculum') || '{}')

    return new Promise<void>((resolve, reject) => {
      // 添加返回 Promise
      const parsedCourses = parseCourses(selected_course_data.value)
      const filteredCourses = []

      for (const course of parsedCourses) {
        const validOptions = []
        for (const option of course.options) {
          // 教学班代码过滤
          if (config.courseCodes.length > 0 && config.courseCodes.includes(option.code)) {
            validOptions.length = 0
            validOptions.push(option)
            break
          }

          // 禁止时间段检查
          const hasForbidden = option.fragments.some((frag: any) => {
            const day = frag.day
            const startPeriod = parseInt(frag.time_slot.slice(1))
            return config.forbidden.has(JSON.stringify([day, startPeriod]))
          })

          if (!hasForbidden) {
            validOptions.push(option)
          }
        }

        if (validOptions.length > 0) {
          filteredCourses.push({
            course_name: course.course_name,
            options: validOptions,
          })
        } else {
          console.error(`课程 ${course.course_name} 没有可用选项`)
          ElMessage.warning(`课程 ${course.course_name} 没有可用选项`)
          resolve() // 添加 resolve
          return
        }
      }

      // 生成所有组合
      const allOptions = filteredCourses.map(c => c.options)
      const allCombinations = cartesianProduct(allOptions)
      // 提示所有组合数量，确定后开始计算

      const isFirstOpen = localStorage.getItem('generate_first_open') === 'true'

      if (isFirstOpen) {
        // 首次打开直接开始计算
        localStorage.setItem('generate_first_open', 'false')
        calculateSchedules(allCombinations, config)
      } else {
        ElMessageBox.confirm(`所有组合数量：${allCombinations.length}，确定开始计算吗？`, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
        })
          .then(() => {
            calculateSchedules(allCombinations, config)
          })
          .catch((e: any) => {
            console.log(e)
            reject(new Error('用户取消操作'))
          })
      }

      function calculateSchedules(allCombinations: any[], config: any) {
        // 筛选有效组合
        const valid = []
        for (const combination of allCombinations) {
          // 检查是否符合要求
          if (isValidSchedule(combination, config.allowed)) {
            valid.push(combination)
            if (valid.length >= 50) break
          }
        }

        // 生成最终课表
        const result = valid.map((combination: any) => {
          const curriculumCopy = JSON.parse(JSON.stringify(curriculum.value))

          // 遍历每个课程组合
          combination.forEach((course: any) => {
            // 遍历课程的所有片段
            for (const frag of course.fragments) {
              // 查找对应时间段
              const timeStr = selected_course_data.value.TimeMap[frag.time_slot].replace(/\r/g, '')
              const timeSlot = curriculumCopy.schedules.find((ts: any) => ts.time === timeStr)

              if (!timeSlot) continue

              // 获取对应的星期字段名
              const weekday = weekdayMap[frag.day as keyof typeof weekdayMap]

              // 初始化时间段数据
              if (!timeSlot[weekday]) {
                timeSlot[weekday] = []
              }

              // 添加课程信息到课表
              timeSlot[weekday].push({
                course_code: course.code,
                course_name: course.name,
                course_teacher: frag.teacher,
                course_week_room: [
                  {
                    course_room: frag.room,
                    course_weeks: frag.weeks,
                  },
                ],
              })
            }
          })

          return curriculumCopy
        })

        validSchedules.value = valid
        allCurriculums.value = result
        ElMessage.success(
          `计算成功，${valid.length === 50 ? '已生成前' : '共'} ${valid.length} 个课表`
        )
        resolve()
      }
    })
  }

  return {
    validSchedules,
    allCurriculums,
    generate,
  }
}
